﻿using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
using PoolGame2.Player;
using PoolGame2.Managers;

namespace PoolGame2.Networking
{
    public class NetworkManager : ManagerNetwork
    {
        PacketReader packetReader = new PacketReader();
        PacketWriter packetWriter = new PacketWriter();
        public NetworkSession netSession;

        public List<PlayerPresence> connectedPlayers = new List<PlayerPresence>(2);

        public NetworkManager(PoolGame game)
            : base(game)
        {

        }

        public NetworkSessionState GetNetworkState()
        {
            return netSession.SessionState;
        }

        public void HostSession(NetworkSessionType type)
        {
            netSession = NetworkSession.Create(type, 2, 2);
            netSession.GamerJoined += GamerJoinedEventHandler;
            netSession.GamerLeft += GamerLeftEventHandler;
            netSession.SessionEnded += SessionEndedEventHandler;
            netSession.GameEnded += GameEndedEventHandler;
            netSession.GameStarted += GameStartedEventHandler;

            PoolGame pGame = (PoolGame)Game;
            pGame.InitialiseGame();
        }

        public void JoinSession(AvailableNetworkSession sess)
        {
            netSession = NetworkSession.Join(sess);
            netSession.GamerJoined += GamerJoinedEventHandler;
            netSession.SessionEnded += SessionEndedEventHandler;
            netSession.GameEnded += GameEndedEventHandler;
            netSession.GameStarted += GameStartedEventHandler;

            ((PoolGame)(Game)).InitialiseGame();
        }

        public void Shutdown()
        {
            if (netSession.IsHost && netSession.SessionState == NetworkSessionState.Playing)
                netSession.EndGame();

            netSession.Dispose();
            netSession = null;
            connectedPlayers.Clear();
        }

        void GamerJoinedEventHandler(object sender, GamerJoinedEventArgs e)
        {
            PoolGame pGame = (PoolGame)Game;
            if( e.Gamer.IsLocal )
                e.Gamer.Tag = new LocalNetworkPlayer(PlayerPresence.PlayerType.PLAYER_LOCAL_LIVE, pGame);
            else
                e.Gamer.Tag = new RemoteNetworkPlayer(PlayerPresence.PlayerType.PLAYER_REMOTE_LIVE, pGame);
            connectedPlayers.Add((PlayerPresence)(e.Gamer.Tag));

            pGame.eventManager.FireEvent(new GameEvent((int)(GameEventID.NIXON_SAY), e.Gamer.Gamertag + " has joined the game."));
        }

        void GamerLeftEventHandler(object sender, GamerLeftEventArgs e)
        {
            PoolGame pGame = (PoolGame)Game;
            pGame.EndGame();
            connectedPlayers.Remove((PlayerPresence)(e.Gamer.Tag));

            pGame.eventManager.FireEvent(new GameEvent((int)(GameEventID.NIXON_SAY), e.Gamer.Gamertag + " has left the game."));
        }

        void GameStartedEventHandler(object sender, GameStartedEventArgs e)
        {
            if (netSession.IsHost)
                return;

            PoolGame pgame = (PoolGame)Game;
            pgame.BeginGame();
        }

        void GameEndedEventHandler(object sender, GameEndedEventArgs e)
        {
            PoolGame pgame = (PoolGame)Game;
            pgame.EndGame();
        }

        void SessionEndedEventHandler(object sender, NetworkSessionEndedEventArgs e)
        {
            PoolGame pgame = (PoolGame)Game;
            pgame.EndGame();
        }

        public override void Update(GameTime gameTime)
        {
            if (netSession == null)
                return;

            PoolGame pgame = (PoolGame)Game;

            if (netSession.IsHost && connectedPlayers.Count > 1
                && netSession.SessionState == NetworkSessionState.Lobby && netSession.IsEveryoneReady )
            {
                pgame.BeginGame();
            }

            foreach (PlayerPresence player in connectedPlayers)
                player.Update(gameTime);

            netSession.Update();

            if (netSession == null)
                return;

            ReadNetworkInput();
            //WriteNetworkOuptput();
        }

        public void ReadNetworkInput()
        {
        }

        public void WriteNetworkOuptput()
        {
            foreach (LocalNetworkGamer gamer in netSession.LocalGamers)
            {
                PlayerPresence pres = (PlayerPresence)(gamer.Tag);
                pres.PackAction( packetWriter, gamer);

            }
        }

        public void WriteNetworkOuptput( PlayerPresence plr, int type, String info)
        {
            foreach (LocalNetworkGamer gamer in netSession.LocalGamers)
            {
                packetWriter.Write(type);
                packetWriter.Write(info);
                gamer.SendData(packetWriter, SendDataOptions.None, plr.GetNetworkGamer());

            }
        }

        public void WriteNetworkOuptput(PlayerPresence plr, int type, byte[] info )
        {
            foreach (LocalNetworkGamer gamer in netSession.LocalGamers)
            {
                packetWriter.Write(type);
                packetWriter.Write(info);
                gamer.SendData(packetWriter, SendDataOptions.None, plr.GetNetworkGamer());

            }
        }

        public void WriteNetworkOuptput(PlayerPresence plr, int type, int info)
        {
            foreach (LocalNetworkGamer gamer in netSession.LocalGamers)
            {
                packetWriter.Write(type);
                packetWriter.Write(info);
                gamer.SendData(packetWriter, SendDataOptions.None, plr.GetNetworkGamer());

            }
        }

        public void WriteNetworkOuptput(PlayerPresence plr, int type, Vector3 vec )
        {
            foreach (LocalNetworkGamer gamer in netSession.LocalGamers)
            {
                packetWriter.Write(type);
                packetWriter.Write(vec);
                gamer.SendData(packetWriter, SendDataOptions.None, plr.GetNetworkGamer());

            }
        }

        public void WriteNetworkOuptput(PlayerPresence plr, int type, Vector3 vec, Vector3 vec2)
        {
            foreach (LocalNetworkGamer gamer in netSession.LocalGamers)
            {
                packetWriter.Write(type);
                packetWriter.Write(vec);
                packetWriter.Write(vec2);
                gamer.SendData(packetWriter, SendDataOptions.None, plr.GetNetworkGamer());

            }
        }

        public void Draw(GameTime gameTime)
        {
            if (netSession == null)
                return;

            PoolGame pGame = (PoolGame)Game;
            SpriteFont font = pGame.fontDatabase.loadFont("Courier New");
            int height = 5;
            int width = pGame.GraphicsDevice.Viewport.Width - (pGame.GraphicsDevice.Viewport.Width / 3);
            Color textColor = Color.Black;
            pGame.spriteBatch.Begin(SpriteBlendMode.AlphaBlend);

            pGame.spriteBatch.DrawString(font, "Current Network State: " + netSession.SessionState, new Vector2(width, height), textColor);
            height += font.LineSpacing;
            pGame.spriteBatch.DrawString(font, "Currently Connected Players State: " + netSession.AllGamers.Count, new Vector2(width, height), textColor);
            height += font.LineSpacing;
            pGame.spriteBatch.DrawString(font, "Session Properties: " + netSession.SessionProperties.Count, new Vector2(width, height), textColor);
            height += font.LineSpacing;

            foreach (NetworkGamer gamer in netSession.AllGamers)
            {
                pGame.spriteBatch.DrawString(font, "-- " + gamer.Gamertag + " : " + gamer.RoundtripTime.Milliseconds, new Vector2(width, height), textColor);
                height += font.LineSpacing;
            }
            pGame.spriteBatch.End();
        }
    }
}
